package sky.controllers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import sky.domain.Card;
import sky.domain.Flight;
import sky.domain.Ticket;
import sky.domain.User;
import sky.exceptions.bookTicketException;
import sky.service.CardService;
import sky.service.FlightService;
import sky.service.TicketService;
import sky.service.UserService;
import sky.tro.TicketFinder;
import sky.tro.TicketList;
import sky.tro.TicketParameters;

import javax.servlet.http.HttpSession;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * User: Gauss
 * Date: 11.05.13
 * Time: 11:12
 * To change this template use File | Settings | File Templates.
 */
@Controller
@SessionAttributes("request")
public class BookingFlightController {

    @Autowired
    private FlightService flightService;
    @Autowired
    private TicketService ticketService;
    @Autowired
    private UserService userService;
    @Autowired
    private CardService cardService;

    @RequestMapping(value = "/findFlight", method = RequestMethod.GET)
    public String findFlight(Map<String, Object> map) {
        map.put("flightCriteria", new TicketFinder());
        return "findFlight";
    }

    @InitBinder
    public void initBinder(WebDataBinder webDataBinder) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yy HH:mm", Locale.ENGLISH);
        dateFormat.setLenient(false);
        webDataBinder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
    }

    @RequestMapping(value = "/findFlight", method = RequestMethod.POST)
    public String findFlight(@ModelAttribute("flightCriteria") TicketFinder finder,
                             BindingResult result, Map<String, Object> map) {
        Map<String, Object> sessionMap = new HashMap<String, Object>();
        sessionMap.put("finder", finder);
        map.put("request", sessionMap);
        return "redirect:/bookingFlight?sort=id";
    }

    @RequestMapping(value = "/bookingFlight", method = RequestMethod.GET)
    public String bookingFlight(@RequestParam("sort") String sortStr,
                                @ModelAttribute("request") Map<String, Object> sessionMap,
                                Map<String, Object> map) {
        TicketFinder finder = (TicketFinder) sessionMap.get("finder");
        map.put("flightList", flightService.FindByFinder(finder, sortStr, finder.getTicketType()));
        map.put("ticketType", finder.getTicketType());
        return "bookingFlight";
    }

    @RequestMapping(value = "/flights/book/{flightId}", method = RequestMethod.GET)
    public String personals(@PathVariable("flightId") Integer id,
                            @ModelAttribute("request") Map<String, Object> sessionMap,
                            Map<String, Object> map) {
        Flight flight =  flightService.getFlightById(id);
        TicketFinder finder = (TicketFinder) sessionMap.get("finder");
        List<Ticket> tickets = new ArrayList<Ticket>();
        User user = getCurrentUser();
        tickets.add(new Ticket(flight, user, finder.getTicketType()));
        for (int i=0; i<finder.getTicketCount()-1; i++) {
            tickets.add(new Ticket());
        }
        map.put("tickets", new TicketList(tickets));
        Integer maxRows = flight.getPlane().getRows();
        Integer[] rows = new Integer[maxRows];
        for (int i = 1 ; i <= maxRows; i++) {
            rows[i-1] = i;
        }
        map.put("rowsCount", rows);
        Integer maxPlaces = flight.getPlane().getPlaces();
        Character[] places = new Character[maxPlaces];
        char i = 'A';
        for (int j = 0; j < maxPlaces; j++) {
            places[j] = i;
            i++;
        }
        map.put("placesCount", places);
        sessionMap.put("flight", flight);
        sessionMap.put("ticketType", finder.getTicketType());
        return "personals";
    }

    /*@RequestMapping(value = "/bookingParameters", method = RequestMethod.GET)
    public String bookingParameters(@RequestParam("id") Integer id, Map<String, Object> map) {
//        for (Ticket ticket: tickets) {
//            ticket.setFlight(flightService.getFlightById(id));
//        }
        map.put("flight", flightService.getFlightById(id));
        map.put("ticket", new TicketParameters(id));
        return "bookingParameters";
    }*/

    /*@RequestMapping(value = "/bookingParameters", method = RequestMethod.POST)
    @SuppressWarnings("unchecked")
    public String bookingParameters(@ModelAttribute("ticket") TicketParameters ticket,
                                    Map<String, Object> map) {
        Set<Ticket> tickets;
        Flight flight = flightService.getFlightById(ticket.getFlightId());
        User user = getCurrentUser();
        Boolean auth = false;
        if (SecurityContextHolder.getContext().getAuthentication().getPrincipal() instanceof UserDetails)
            auth = true;
        tickets = new HashSet<Ticket>(ticket.getTicketCount());
        for (Integer i = 0; i < ticket.getTicketCount(); i++) {
            tickets.add(new Ticket(flight, user, ticket.getTicketType()));
        }
        map.put("request", tickets);
        if (auth) {
            return "redirect:/bookingForm";
        }
        else {
            return "redirect:/bookingLogin";
        }
    }*/

    User getCurrentUser() {
        Object object = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String name;
        if (object instanceof UserDetails) {
            name = ((UserDetails) object).getUsername();
        }
        else {
            name = object.toString();
        }
        return userService.getUserByName(name);
    }

    /*@RequestMapping(value = "/bookingLogin", method = RequestMethod.GET)
    public String bookingLogin() {
        return "bookingLogin";
    }*/

    /*@RequestMapping(value = "/bookingForm", method = RequestMethod.GET)
    public String bookingForm(@ModelAttribute("request") HashSet<Ticket> request, Map<String, Object> map) {
        Integer number = request.size();
        List<User> list = new ArrayList<User>(number);
        list.add(getCurrentUser());
        for (Integer i = 0; i <= number - 2; i++) {
            list.add(new User());
        }
        map.put("users", list);
        return "bookingForm";
    }*/

    /*@RequestMapping(value = "/bookingForm", method = RequestMethod.POST)
    public String bookingForm(@ModelAttribute("request") HashSet<Ticket> request,
                              @ModelAttribute("users") ArrayList<User> users,
                              Map<String, Object> map,
                              BindingResult result) {
        if (request.iterator().hasNext()) {
            Ticket ticket = request.iterator().next();
            try {
                flightService.bookTickets(ticket.getFlight().getId(), request.size(), ticket.getType());
            } catch (bookTicketException exception) {
                map.put("error", exception.getMessage());
                return "error";
            }
        }
        return "index";
    }*/

    @RequestMapping(value = "flights/book/*", method = RequestMethod.POST)
    public String confirmPersonals(@ModelAttribute("tickets") TicketList ticketList,
                                   @ModelAttribute("request") Map<String, Object> sessionMap,
                                   BindingResult result) {
        sessionMap.remove("tickets");
        ArrayList<Ticket> tickets = (ArrayList<Ticket>) ticketList.getTicketList();
        Flight flight = (Flight) sessionMap.get("flight");
        String ticketType = (String) sessionMap.get("ticketType");
        for (Ticket ticket: tickets) {
            ticket.setFlight(flight);
            ticket.setType(ticketType);
        }
        sessionMap.put("tickets", tickets);
        return "redirect:/payment";
    }

    @RequestMapping(value = "payment", method = RequestMethod.GET)
    @SuppressWarnings("unchecked")
    public String payment(@ModelAttribute("request") Map<String, Object> sessionMap,
                          Map<String, Object> map) {
        ArrayList<Ticket> tickets = (ArrayList<Ticket>) sessionMap.get("tickets");
        Integer adultNumber = 0, childNumber = 0;
        Integer adultCost = 0;
        for(Ticket ticket: tickets) {
            if (!ticket.getUser().getChild()) adultNumber++;
            else childNumber++;
            adultCost = ticket.getFlight().getCostByType(ticket.getType());
        }
        map.put("adultNumber", adultNumber);
        map.put("childNumber", childNumber);
        map.put("adultCost", adultCost);
        Integer childCost = (int)(adultCost*0.9);
        map.put("childCost", childCost);
        map.put("card", new Card());
        User user = getCurrentUser();
        ArrayList<Integer> cards = new ArrayList<Integer>();
        if (user != null) {
            for (Card card: user.getCards()) {
                cards.add(card.getCardId());
            }
        }
        if (user != null) map.put("cards", cards);
        else map.put("cards", null);
        return "payment";
    }

    @RequestMapping(value = "addCard", method = RequestMethod.POST)
    @SuppressWarnings("unchecked")
    public String addCard(@ModelAttribute("request") Map<String, Object> sessionMap,
                          @ModelAttribute("card") Card card,
                          BindingResult result) {
        User user = getCurrentUser();
        ArrayList<Ticket> tickets = (ArrayList<Ticket>) sessionMap.get("tickets");
        if (user != null) {
            card.setUser(user);
            cardService.addCard(card);
        }
        for (Ticket ticket: tickets) {
            if (ticket.getUser().getId() == null) {
                User user1 = ticket.getUser();
                user1.setName("anon");
                user1.setRole("ROLE_ANONYMOUS");
                ticket.setUser(user1);
                userService.addUser(user1);
            }
        }
        Flight flight = (Flight)sessionMap.get("flight");
        flightService.bookTickets( flight.getId(),
                tickets.size(),
                (String) sessionMap.get("ticketType"));
        for (Ticket ticket: tickets) {
            ticketService.bookTicketByPlace(flight.getId(), ticket.getRow(), ticket.getPlace(), ticket.getUser().getId());
        }
        return "redirect:/index";
    }
}
